
延續昨天的主題 Vuetify 中用到的技術大方向有:
接下來幾天會利用 Vuetify 的 WebpackSSR 模板,邊解釋邊學習上面這些東西,搞定這些技術後,就擁有了一個完整的開發流程了。
先從 vue-router 開始!
我們可以簡單的透過 Vue.js + vue-router 來建立一個 Single Page Application(SPA)。
經過了前面對 Vue.js 的學習,已經可以透過元件(Component)來組合應用程式。
而當我們想要將 vue-router 加入專案時,我們需要將元件映射到路由(routes),然後告訴 vue-router 在何處渲染。
先看一個基本的使用 vue-router 的範例:
<div id="app">
  <h1>Hello App!</h1>
  <p>
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <router-view></router-view>
</div>
const Foo = { template: '<div>foo</div>' };
const Bar = { template: '<div>bar</div>' };
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
];
const router = new VueRouter({
  routes
});
const app = new Vue({
  router
}).$mount('#app');
附上 codepen 連結 (https://codepen.io/hunterliu1003/pen/ZvyJrM)
看完簡單範例後,回到 Vuetify 的模板 WebpackSSR(可先回上一篇看快速開始的教學)。
附上 WebpackSSR 的目錄結構,方便對照:
在 Vuetify WebpackSSR(以下簡稱VW)的目錄結構中,所有關於 vue-router 的東西都放在 router 資料夾。透過router中的index.js建立createRouter,並在assets中的app.js引入,並且將實體化的Router物件作為屬性傳入 Vue instance 中。
看一下程式碼的片段(如果想看到結果請依照上一篇的懶人包安裝):
程式碼解釋的部分就直接寫在註解,因為想不到更好的方式,程式碼一多為了避免失焦就這樣子吧。
router/index.js
import Vue from 'vue'
import Router from 'vue-router'
const meta = require('./meta.json')
// meta.json 中用json格式定義了所有的路由的 meta 標籤。
// 切換頁面時,html中的meta標籤內容會根據 meta.json 中的設定更新。
function route (path, view) {
  return {
    path: path,
    // 網址列上的路徑
    meta: meta[path],
    // 根據該路徑(path)的meta屬性設定為meta.json中所屬的路由物件
    component: resolve => import(`pages/${view}View.vue`).then(resolve)
    // 這裡引入的.vue檔是指資料夾pages中的Single File Component。
    // 資料夾components中放的則不需要是用 v-layout 包覆的自定義元件。
  }
}
Vue.use(Router)
// 使用 plugin 的方法,可參考(https://vuejs.org/v2/guide/plugins.html#Using-a-Plugin)
export function createRouter () {
    const router = new Router({
      base: __dirname,
      mode: 'history',
      scrollBehavior: () => ({ y: 0 }),
      routes: [
        route('/', 'Welcome'),
        route('/inspire', 'Inspire'),
        { path: '*', redirect: '/' }
      ]
      // routes 定義所有的路由,此處只有'/'和'/inspire'兩個頁面
      // { path: '*', redirect: '/' } 是為了處理未定義的路由,將頁面導到首頁(/)。
    })
    router.beforeEach((to, from, next) => {
        if (typeof ga !== 'undefined') {
            ga('set', 'page', to.path)
            ga('send', 'pageview')
        }
        next()
    }) // google analytics 可略過。
    return router
}
assets/app.js
import Vue from 'vue'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.css'
import App from './App.vue'
import Components from 'components/_index'
import { createStore } from 'store/index'
import { createRouter } from 'router/index'
import { sync } from 'vuex-router-sync'
Vue.use(Vuetify)
Object.keys(Components).forEach(key => {
  Vue.component(key, Components[key])
})
export function createApp (ssrContext) {
  const store = createStore() // 實體化 vuex 下篇回提到
  const router = createRouter() // 實體化 router = new Router({options})
  sync(store, router)
  // 透過 vuex-router-sync 同步 vuex 和 vue-router,會同步的屬性有 {
  //   path: '',
  //   query: null,
  //   params: null
  // }
  // 主要是將 vue-router 的狀態放進 vuex 的 state 中,透過改變 state 進行路由的操作。
  // 這使我們可以輕鬆透過以下方法取得或操作路由設定:
  // store.state.route.path   // current path (string)
  // store.state.route.params // current params (object)
  // store.state.route.query  // current query (object)
  const app = new Vue({
    router,
    store,
    ssrContext, // 之後篇幅會補充
    render: h => h(App)
    // h => h(App)中的App為資料夾assets中的App.vue,App.vue是這整個SPA最核心基礎的頁面組成。
  })
  // 將 router, store, ssrContext, render 傳入選項物件中
  return { app, router, store }
}